/**
 * 1.事件监听API：
 * 以 on 开头的 API 用来监听某个事件是否触发，如：wx.onSocketOpen，wx.onCompassChange 等，这类 API 接 
 * 受一个回调函数作为参数，当事件触发时会调用这个回调函数，并将相关数据以参数形式传入
 * 2.同步API
 * 以 Sync 结尾的 API 都是同步 API， 如 wx.setStorageSync，wx.getSystemInfoSync 等。此外，也有一些其
 * 他，的同步 API，如 wx.createWorker，wx.getBackgroundAudioManager 等，详情参见 API 文档中的说明。
 * 3.异步API 
 * 大多数 API 都是异步 API，如 wx.request，wx.login 等。这类 API 接口通常都接受一个 Object 类型的参
 * 数，这个参数都支持按需指定以下字段来接收接口调用结果
 * 4.列表渲染
 * A：wx:for ： 默认数组的当前项的下标变量名默认为 index，数组当前项的变量名默认为 item
 * 使用 wx:for-item 可以指定数组当前元素的变量名，
 * 使用 wx:for-index 可以指定数组当前下标的变量名
 * B：block wx:for ：也可以将 wx:for 用在<block/>标签上，以渲染一个包含多节点的结构块
 * 5.条件渲染
 * A：wx:if  ：在框架中，使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块：
 *      也可以用 wx:elif 和 wx:else 来添加一个 else 块
 * B：block wx:if ：因为 wx:if 是一个控制属性，需要将它添加到一个标签上。如果要一次性判断多个组件标签，
 * 可以使用一个 <block/> 标签将多个组件包装起来，并在上边使用 wx:if 控制属性。
 * 6.事件
 * A：bindtap  ：当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数
 * B：事件绑定和冒泡：bind事件绑定不会阻止冒泡事件向上冒泡，catch事件绑定可以阻止冒泡事件向上冒泡。
 * C：事件的捕获阶段：触摸类事件支持捕获阶段。捕获阶段位于冒泡阶段之前，且在捕获阶段中，事件到达节点的顺序
 * 与冒泡阶段恰好相反。需要在捕获阶段监听事件时，可以采用capture-bind、capture-catch关键字，后者将中断捕
 * 获阶段和取消冒泡阶段
 * D：事件对象：当组件触发事件时，逻辑层绑定该事件的处理函数会收到一个事件对象
 * 7.模版：在模版中给组建添加点击事件或样式等，这个事件必须添加到引用的JS文件中，不能添加到模版的JS文件中（添加在模
 * 版的JS文件中会找不到）
 * 8.引用：import可以在该文件中使用目标文件定义的template
 * A：import 的作用域：import 有作用域的概念，即只会 import 目标文件中定义的 template，而不会 import 目
 * 标文件 import 的 template。
 * B：include：可以将目标文件除了 <template/> <wxs/> 外的整个代码引入，相当于是拷贝到 include 位置
 * include要比import导入的功能要强大
 * 9.样式导入：使用@import语句可以导入外联样式表，@import后跟需要导入的外联样式表的相对路径，用;表示语
 * 句结束
 * 10.注意事项：
 * A：在模版中不能动态的改变样式，如需改变必须在使用的页面进行改变，
 * B：微信小程序设计的基准是iPhone6，所以在开发过程中要用phone6当模拟器
 * C;当引入工具类的时候在page的外边，不能用this进行调用，因为这个this指的是page内部的对象，外部属性直接调
 * 用即可
 * D：em 是根据字体大小来确定的 1em = 一个字体大小
 * E：文字段落首行缩近：text-indent: 2em;
 * F：文本对齐问题：text-aling
 * G: setData尽量少用，调用一次setData就会进行一次，逻辑层与试图层的数据交互，并刷新UI，（在开发过程中尽量将
 * H:当scroll-view的父级设置为position: fixed时scroll-view不能滑动，需要scroll-view的父级设为
 * width为100%
 * I:能合并的 setData放在一起减少阻塞的次数）
 * J: width: auto;相当于android中的包裹内容
 * K:让元view中的内容居中的办法，text-align: center;必须要与line-height: 100rpx;配合使用
 * L:行高居中的方法要将line-height 设置为与父窗体一样高，如果小于父窗体则文字偏上，如果大于父窗体则文字偏下
 * 11.组建基础
 * 12.表单from
 * 表单将组件内用户输入的<switch><input><checkBox><slider><radio><picker>提交。点击<from>表单中的
 *  form-type 为 submit 的 <button> 组件时，会将表单组件中的 value 值进行提交，需要在表单组件中加上 
 * name 来作为 key。
 * 13.页面跳转
 * wx.navigateBack(Object object)关闭当前页面，返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈，决定需要返回几层。
 * wx.navigateTo(Object object)保留当前页面，跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。
 * wx.redirectTo(Object object)关闭当前页面，跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。
 * wx.reLaunch(Object object)关闭所有页面，打开到应用内的某个页面
 * wx.switchTab(Object object)跳转到 tabBar 页面，并关闭其他所有非 tabBar 页面
 * 14.微信最适合的布局使用弹性布局，display:flex弹性布局中可以指定弹性盒子的方向，flex-direction: column;内容水平居中使用lign-items: center;文字垂直居中使用文字控件的行高与父容器的行高一致，line-height = 父容器的高度
 * 15.scroll-view横向不能滚动的问题：（https://blog.csdn.net/xiaochun365/article/details/71213912）
 * 设置scroll-view的white-space: nowrap（文本不会换行，文本会在在同一行上继续，直到遇到br 标签为止）
 * 关于white-space属性值的解释：normal 默认。规定段落中的文本不进行换行,空白会被浏览器忽略。
    pre 空白会被浏览器保留。其行为方式类似 HTML 中的 pre 标签。
    nowrap 文本不会换行，文本会在在同一行上继续，直到遇到br 标签为止。
    pre-wrap 保留空白符序列，但是正常地进行换行。
    pre-line 合并空白符序列，但是保留换行符。
    inherit 规定应该从父元素继承 white-space 属性的值
    在scroll-view的每个item原属要使用display: inline-block;:应用此特性的元素呈现为内联对象，周围元素保持在同一行
    16.微信小程序使用的拍照与照片选择使用的API是wx.chooseImage(Object object)根据指定sourceType来区分图片的来源，album代表从相册选图，camera代表使用相机得到图片
    17.微信小程序查看大图使用的API是：wx.previewImage(Object object)
    18.this.setData()的详细使用:用{{}}包起来的就是一个对象，setData()表示将内容添加到data上，并且刷
    新UI
    19.小程序对包大小的要求：
      小程序对所以的分包与主包大小不能超过8M，单包大小不能超过2M（包含主包与分包）
      分包要进行分包技术与预下载分包技术的实现
    20.对 “...”的解释：
    ... 是es6 的展开运算符（也就是将{}退去）
    21.微信小程序数据绑定是单项的的，就不是双向的，他只能从data 更新数据到UI，不能从UI更新数据到Data
    22.微信小程序在如果在onload方法中有需要直接赋值的可以直接用=号，如果是异步的必须使用setData()进行赋值（对赋值后的数据进行刷新界面）
    23. 子页面修改父页面的值（完成）
 * 实现方法： 将父级页面的数据修改后，回到父级页面进行刷新（在子页面刷新父级页面不可用）
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 *  
 * 页面深度不超过5级，（没测试出来，状态：完成）
 * this.setData()的详细使用 
 *  用{{}}包起来的就是一个对象，setData()表示将内容添加到data上，并且刷新UI，
 * vertical-align: 的理解(看的不是很明白)
 * 页面生命周期再次理解(较上一次比较明白点了)
 * 微信开发工具端提交代码（拉取，合并，提交）
 * 微信分包技术的实现
 * 微信预下载分包技术的实现
 * 
 * 
 * template 模版的使用，
 * 绑定数据的再次理解
 * 自定义属性的注意事项
 * 详情页面的再次构建
 * 选择控件的完善
 * 
 * 子页面修改父页面的值（完成）
 * 实现方法： 将父级页面的数据修改后，回到父级页面进行刷新（在子页面刷新父级页面不可用）
 * 微信小程序页面的生命周期：
 * 每次都走的方法是 onShow() 和 onHide()
 * 小程序多线程的学习 
 * 第一步：首先在app.json 中可配置 Worker 代码放置的目录
 * 第二步；创建worker，主线程与子线程可以互相发数据
 * 第三步：用完要进行回收线程
 *  compotent 自定义组件（继续学习）
 * 
 *
 * canvas 学习(现场照片添加水印)   ----> 完成80%，遗留问题：js 如何创建canvas(今天搞的代码丢了)
 * 继续看CSS
 * 了解flutter
 * 
 * 
 * 
 * css 之 flex 弹性盒子布局：
 * flex:属性相当于Android中的权重布局，属性值代表他在改容器的占比
 * flex-grow:属性表示占剩余空间的比例
 * flex-direction:属性排列方式（决定flex需要如何进行排列）
 * flex-wrap：该属性控制flex容器是单行或者多行，同时横轴的方向决定了新行堆叠的方向
                    nowrap：flex容器为单行。该情况下flex子项可能会溢出容器
                    wrap：flex容器为多行。该情况下flex子项溢出的部分会被放置到新行，子项内部会发生断行
                    wrap-reverse：反转 wrap 排列。
 * 
 * align-content：本属性可以用来调准「伸缩行」在伸缩容器里的对齐方式
 * justify-content 与 align-content 都是在伸缩容器里的对其方式，一个是横向，一个纵向
 * 
 * 文本样式：text-align 定义元素内容的水平对齐方式。
 * 定位样式：position 用于指定一个元素在文档中的定位方式
 * absolute 对象会脱离常规流
 * 
 * 
 * 
 * 创业项目：快递餐自动放
 * 企业与物业合作，一个楼层租一块小地方（1000元）与外卖平台合作 放一个快递5毛钱,一个机器一个月
 * 挣500元，在北京铺设10000台机器，一个月挣500万，一年：6000W，去掉3000W的运营成本，一年挣3000W
 * //=======================Android=========================================
 * activity 之通信
 *  1.intent/bundle
 *  2.全局变量（创建一个全局变量的类，去修改全局属性的值）
 * 
 * activity 将数据传递给fragment
 * 1.bundle
 * 2.直接在activity中定义方法（在fragment中获取activity对象，并可以拿到对应的属性）
 * 
 * fragment 与 activity
 * 1.在fragment内定一个一个内部回调接口
 * 2.在fragment里onattach()获取activity对象，调用activity赋值方法，最后调用onDetach
 * （）方法将activity对象释放掉。
 * 
 * activity 与server数据通信
 * 1.绑定服务，利用ServiceConnection 类传递（其实这个也是用的回调的思想）
 * 2.简单通信用intent
 * 3.定义一个callback接口来监听服务中的进程变化
 * 
 * singleTop 的应用场景
 * 1.IM聊天页面
 * 2.新闻客户端的推送也（从通知栏点击进去在栈定就不需要创建，继续使用）
 * 
 * singletask的应用场景
 * 首页
 * 
 * 
 * singleinstance的应用场景
 * 一个应用调用另一个应用的页面
 * 
 * URL 与 URI 的区别
 * 
 * URL是统一资源定位符
 * 1.协议
 * 2.存在该资源的主机IP地址，着重强调路径
 * 3.主机资源的具体地址
 * URI是统一资源标识符
 * 1.访问资源的命名机制
 * 2.存放资源的主机名
 * 3.资源的自身名称由路径表示，着重强调资源
 * 
 * Service 中的内容
 *1. 服务与其他应用程序对象一样，在其托管进程的主线程中运行，这就意味这服务里不能进行耗时的操作
 服务的生命周期：startService（）的生命周期 oncreate() --> onStartCommand 一直处于运行状态，除非手动停止服务
 2.其他应用访问这个服务，在清单<service> 标签中声明服务时，可以强制执行对服务的全局访问。通过这样做，其他应用程序将需要<uses-permission> 在其自己的清单中声明相应的 元素，以便能够启动，停止或绑定到服务。
 3.intentservice是这种“工作队列处理器”模式通常用于从应用程序的主线程卸载任务。存在IntentService类以简化此模式并处理机制。要使用它，请扩展IntentService并实现onHandleIntent(Intent)。IntentService将接收Intents，启动工作线程，并根据需要停止服务。
 
 *注意： IntentService受到 Android 8.0（API级别26）强加的所有 后台执行限制的约束。在大多数情况下，最好使用JobIntentService，在Android 8.0或更高版本上运行时使用作业而不是服务。
 * 4.JobIntentService
 * 他和intentservice 一样都是在将任务加到队列中，
 * 由于Android O的后台限制，创建后台服务需要使用JobScheduler来由系统进行调度任务的执行，而使用JobService的方式比较繁琐，8.0及以上提供了JobIntentService帮助开发者更方便的将任务交给JobScheduler调度，其本质是Service后台任务在他的OnhandleWork()中进行，子类重写该方法即可。使用较简单
 * jobIntentService 工作原理：（server+AsyncTask）
 * 当调用JobIntentService.enqueueWork()方法会启动服务，oncreate()方法里会里回去server对象，在onStartCommand里创建WorkEnqueuer对象（怎么要进行的耗时操作就在该对象下）然后调用serviceStartReceived（）方法，往组件队列里添加任务，然后执行AsyncTask的后台方法（也就是执行我们的耗时操作）当AsyncTask中的任务执行完后
 * 会回调到onPostExecute（）方法然后结束该服务 
 * 
 * 5.Android界面必须在16ms 完成一帧的绘制。好的Ui界面绘制的帧率在60fps
 * 6.造成UI丢帧的案例有：
 *  layout 过于复杂，层次太多；UI上有太多的成叠绘制单元，过度绘制；GPU，CPU负载过重；
 * 频繁的GC 造成内存抖动；UI线程执行耗时的操作；
 * 7.进程间通信的方法有，使用aidl；使用广播，内容提供者
 * 8.aidl 实现的是进程间的通信；
 * 实现步骤；1.在服务端的main 文件夹下创建aidl文件夹，
 *                 2.然后在生产的接口文件中定义接口方法
 *                 3.在服务端编写service代码，并在onBind返回继承aidl 文件里的Stub对象，
 *                 4.在清单文件进行配置
 *                 5.在客户端复制服务端生存的Java代码（保证包名相同）
 *                 6.进行绑定与解绑服务，绑定是注意添加service的包名
 *                 Intent intent = new Intent();
                   //从 Android 5.0开始 隐式Intent绑定服务的方式已不能使用,所以这里需要设置Service所在服务端的包名
                    intent.setAction("drmfab.cn.androidnew.MyBindService");
                    intent.setPackage("drmfab.cn.androidnew");
                    MainActivity.this.bindService(intent,connection,BIND_AUTO_CREATE);
 *9. handler 运行原理：
 hanlder 的构造里会获取当前线程的looper 对象，消息队列，callback对象
  Loop.prepare （）这个方法里将创建的Loopre 对象添加到sThreadLocal容器里，然后looper的构造方法
  里创建里，消息队列MessageQueue，并且获取当前的线程，这样looper 就与thread messageQueue关联，
  然后在看looper.Loop()这个方法，loop（）里边是一个死循环，当发现消息不为空的话，她就会mCallback.handleMessage（）,也就是怎么handler实现的handler.callback()方法
 * 
 * 
 * 
 * intentService 的源码解析
 * intentservice 第一步；在increate 方法里创建线程handlerthread 并开启线程，创建handler对象并，将改线程的looper对象赋值给handler，在onstartcommed（）发送消息，
 * 在handler 的handlermessage 中处理消息（执行onhandlerIntent）然后停掉该服务，（所以onhandlerIntent方法是在子线程中执行）
 * 
 * 
 * 
 * 9. handler 运行原理：
 * thread 添加了looper -- handler --> this.looper.mQueue 
 * 这个时候 handler 持有 looper对象，消息队列
 * looper 持有当前的线程对象，消息队列对象
 * 消息队列持有消息对象
 * 说白了handler 就是looper 对象中的回调
 * 
 *                   handler （looper，消息队列） {
 *          mLooper = Looper.myLooper();
 *          mQueue = mLooper.mQueue;
 *          mCallback = callback;
 * }
 *                    looper （消息队列,当前的线程）{
 *        sThreadLocal.set(new Looper(quitAllowed));
 *        private Looper(boolean quitAllowed) {
          mQueue = new MessageQueue(quitAllowed);
          mThread = Thread.currentThread();
      } 
      loop() 死循环---->dispatchMessage()----->handlerMessage()
      }
 * 
 * AsyncTask 的源码解析：
 * 
 * AsyncTask 执行构造时，他调用的三个参数的构造，在构造中传入的是当前线程的Looper对象，然后赋值给了handler对象，使handler 对象
 * 处理消息在主线程，然后开工作线程（子线程），并调用doInBackground（）方法，当线程中的事件处理完毕后，调用handler 发消息，handler收到消息调用onPostExecute（）方法
 * ，所以onPostExecute（）方法是在主线程中执行。（因为该handler绑定是是主线程中的looper）
 * 
 * 10.okhttp：有同步请求和异步请求两种
 * 使用步骤： 创建OKhttpclient -----> 创建request 请求对象----> 通过builder可以配置请求参数和header等------>
 * 调用newCall(request)获取call对象------->调用call对象的execute（）方法进行同步请求（调用enqueue（）方法进行异步请求，回调的方法还是在子线程中）
 * 源码解析：首先进去enqueue（）方法中，该方法中会有一个标志位，判断改改请求是否发起，如果为false，则拦截器进行拦截
 * dispatcher.enqueue(new AsyncCall(responseCallback)); AsyncCall 实际上是一个runnable 对runnable进行来包装，将我们传进去的
 * callback 放到子线程中，enqueue（）方法中进行了判断请求是否超过最大请求数是否超过最大连接数主机数，如果都没有超过则添加到，Java中的并发请求框架中，然后执行runnbale,否则将加入等待队列中。获取回来的数据
 * 回调到callback 方法里，所以callback 方法是在子线程中，不能进行UI操作
 * 
 * 11.retrofit：原理解析
 * 1.解析网络请求接口的注解配置网络请求参数，
 *      调用onCreate(class) 会遍历接口里边的方法，找到要请求的方法将该方法交给serviceMothed(mothed) 这个类是将该注解的方法解析里边的各种参数（网络请求的参数），然后将解析出来的结果与对应的方法名存入网络请求队列中。
 * 2.动态代理生成网络请求参数
 * 3.网络请求适配器将网络请求对象进行平台适配，
 *    ····ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);//取出网络请求队列中的相应参数
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);  获取okhttp 中的call 对象
            return serviceMethod.callAdapter.adapt(okHttpCall)
 * 4.网络请求执行器，发送网络请求
 * 5.数据转换器解析服务器返回的数据
 * 6.回调执行器切换线程
 * 7.主线程处理网络返回的结果
 * 
 * 12.RXJava 原理：
 *  A：需要的条件：观察者，被观察者，订阅，事件
 *  B：使用：创建被观察者（observable）&生产事件 ------->创建观察者（observer)并定义响应事件的行为------>通过订阅（subscribe）连接观察者和被观察者
 *        observer观察者有onNext（），onCompleted()，onError() 重要方法。
 *        Observer 的抽象类Subscriber
 * C：Observable 即被观察者，它决定什么时候触发事件以及触发怎样的事件。 RxJava 使用 create() 方法来创建一个 Observable ，并为它定义事件触发规则：
 * D：subscribe（订阅事件）
 * public Subscription subscribe(Subscriber subscriber) {
    subscriber.onStart();
    onSubscribe.call(subscriber);//出发事件
    return subscriber;}

 * 13.自定义View
 * 
 * 
 * 14.Androidstudio目录说明
 * 
 * 
 * 15.gradle流程
 * 
 * 
 * 16.混淆操作
 * 
 * 
 * 17.Glide的使用与API说明
 * 
 * 
 * 18.Android性能优化
 * 
 * 
 * 性能优化注意：在解除绑定的操作要在onPause()或者onStop()中进行，否则有可能会造成内存泄漏，因为ondesdroy()在没写不确定的情况下不会执行。
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * */